home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / IFC_112 / netscape / application / MenuView.java < prev    next >
Encoding:
Text File  |  1999-05-28  |  28.9 KB  |  929 lines  |  [TEXT/CWIE]

  1. // MenuView.java
  2. // By Ned Etcode
  3. // Copyright 1997 Netscape Communications Corp.  All rights reserved.
  4.  
  5. package netscape.application;
  6.  
  7. import netscape.util.*;
  8.  
  9. /** View subclass managing a Menu. There are two types of MenuViews,
  10.   * <b>HORIZONTAL</b> and <b>VERTICAL</b>. You set this type with the
  11.   * <b>setType</b> method to tell the MenuView how it should arrange
  12.   * its Menu's MenuItems for displaying. MenuViews arrange themselves
  13.   * hierarchically to mirror the structure of their respective Menus, using
  14.   * their <b>owner</b> and <b>child</b> instance variables for traversing.
  15.   * Thus, a top-level
  16.   * MenuView will have a null owner, and the lowest showing MenuView will
  17.   * have a null child. When
  18.   * a MenuView receives a MouseEvent that should show a submenu, a new
  19.   * MenuView is created with its Menu data set appropriately, and then that
  20.   * MenuView is
  21.   * instructed to show. Additionally, the behavior of
  22.   * MouseEvents on the MenuView differs if it manages a top-level Menu. Note
  23.   * that MenuViews manage an InternalWindow that they use to draw into,
  24.   * and this
  25.   * Window is never shown in MenuViews that are designated as static
  26.   * "menu bar" style MenuViews. You usually create a new MenuView with a
  27.   * given Menu, and then set it on a Window with <b>setMenuView</b>. These
  28.   * MenuViews must own a top-level Menu, and are usually of type
  29.   * <b>HORIZONTAL</b>.
  30.   *
  31.   * @see Menu, MenuItem
  32.   *
  33.   * @note 1.0 added support for command key equivalents
  34.   * @note 1.0 added protected method createMenuWindow
  35.   */
  36.  
  37. public class MenuView extends View {
  38.     Menu                menu;
  39.     MenuItem            selectedItem;
  40.     public MenuView     owner, child;
  41.     InternalWindow      menuWindow;
  42.     int                 type, itemHeight = 17;  // ALERT
  43.     boolean             transparent = false;
  44.  
  45.     final static String        MENU_KEY = "menu",
  46.                                OWNER_KEY = "owner",
  47.                                CHILD_KEY = "child",
  48.                                MENUWINDOW_KEY = "menuWindow",
  49.                                MENUITEMHEIGHT_KEY = "itemHeight",
  50.                                TYPE_KEY = "type",
  51.                                TRANSPARENT_KEY = "transparent";
  52.  
  53.  
  54.     public static final int    HORIZONTAL = 0;
  55.     public static final int    VERTICAL = 1;
  56.  
  57.     /** Constructs a MenuView with origin (0, 0) and zero width and height.
  58.       * This MenuView will create its own top-level Menu, will be of type
  59.       * HORIZONTAL, and will have no owner.
  60.       */
  61.     public MenuView() {
  62.         this(0, 0, 0, 0, null, null);
  63.     }
  64.  
  65.     /** Constructs a MenuView with origin (0, 0) and zero width and height.
  66.       * This MenuView will use <b>aMenu</b> to define its structure, and will
  67.       * determine its type by whether or not <b>aMenu</b> is top-level. This
  68.       * MenuView's owner will be null.
  69.       */
  70.     public MenuView(Menu aMenu) {
  71.         this(0, 0, 0, 0, aMenu, null);
  72.     }
  73.  
  74.     /** Constructs a MenuView with bounds (<b>x</b>, <b>y</b>, <b>width</b>,
  75.       * </b>height</b>). This MenuView will create its own top-level Menu,
  76.       * will be of type HORIZONTAL, and will have no owner.
  77.       */
  78.     public MenuView(int x, int y, int width, int height) {
  79.         this(x, y, width, height, null, null);
  80.     }
  81.  
  82.     /** Constructs a MenuView with bounds (<b>x</b>, <b>y</b>, <b>width</b>,
  83.       * </b>height</b>). This MenuView will use <b>aMenu</b> to define
  84.       * its structure, and will determine its type by whether or not
  85.       * <b>aMenu</b> is top-level. This MenuView's owner will be null.
  86.       */
  87.     public MenuView(int x, int y, int width, int height, Menu aMenu) {
  88.         this(x, y, width, height, aMenu, null);
  89.     }
  90.  
  91.     /** Constructs a MenuView with bounds (<b>x</b>, <b>y</b>, <b>width</b>,
  92.       * </b>height</b>). This MenuView will use <b>aMenu</b> to define
  93.       * its structure, and will determine its type by whether or not
  94.       * <b>aMenu</b> is top-level. This MenuView will have <b>anOwner</b>
  95.       * as its owner.
  96.       */
  97.     public MenuView(int x, int y, int width, int height, Menu aMenu,
  98.                     MenuView anOwner) {
  99.         super(x, y, width, height);
  100.         if (aMenu != null) {
  101.             menu = aMenu;
  102.         } else {
  103.             menu = new Menu(true);
  104.         }
  105.         owner = anOwner;
  106.  
  107.         menuWindow = createMenuWindow();
  108.         menuWindow.addSubview(this);
  109.  
  110.         if (menu.isTopLevel()) {
  111.             type = HORIZONTAL;
  112.             setHorizResizeInstruction(WIDTH_CAN_CHANGE);
  113.         } else {
  114.             type = VERTICAL;
  115.         }
  116.  
  117.         // ALERT!  This is the little hack that allows Menus to know
  118.         // about their MenuViews, so that MenuItems can tell the MenuViews
  119.         // to redraw them, and so MenuBorders know how to draw.
  120.         menu.menuView = this;
  121.     }
  122.  
  123.     /** Creates the InternalWindow that is used by this MenuView for
  124.       * displaying its Menu's MenuItems. Note that toplevel MenuViews never
  125.       * use an InternalWindow for drawing, so the returned Object is
  126.       * ignored. Subclasses can override this
  127.       * method to return their own custom subclass of InternalWindow.
  128.       */
  129.     protected InternalWindow createMenuWindow() {
  130.         InternalWindow window;
  131.  
  132.         window = new InternalWindow(0, 0, 0, 0);
  133.         window.setType(InternalWindow.BLANK_TYPE);
  134.         window.setLayer(InternalWindow.IGNORE_WINDOW_CLIPVIEW_LAYER+11);
  135.         window.setCanBecomeMain(false);
  136.         window._contentView.setTransparent(true);
  137.         window.setScrollsToVisible(true);
  138.         return window;
  139.     }
  140.  
  141.     /** Sets this MenuView to be of type <b>aType</b>, either <b>HORIZONTAL</b>
  142.       * or <b>VERTICAL</b>.
  143.       */
  144.     public void setType(int aType) {
  145.         type = aType;
  146.     }
  147.  
  148.     /** Returns this MenuView's type.
  149.       * @see #setType
  150.       */
  151.     public int type() {
  152.         return type;
  153.     }
  154.  
  155.     /** Sets the Menu this MenuView owns.
  156.       */
  157.     public void setMenu(Menu theMenu) {
  158.         menu = theMenu;
  159.     }
  160.  
  161.     /** Returns the Menu this MenuView owns.
  162.       */
  163.     public Menu menu() {
  164.         return menu;
  165.     }
  166.  
  167.     /** Sets <b>menuView</b> as the owner of this MenuView.  A MenuView's
  168.       * owner is the MenuView that hierarchically displays this MenuView.
  169.       */
  170.     public void setOwner(MenuView menuView) {
  171.         owner = menuView;
  172.     }
  173.  
  174.     /** Returns the owner of this MenuView.
  175.       * @see #setOwner
  176.       */
  177.     public MenuView owner() {
  178.         return owner;
  179.     }
  180.  
  181.     /** Returns the background Color of the MenuView's Menu.
  182.       */
  183.     public Color backgroundColor() {
  184.         return menu.backgroundColor();
  185.     }
  186.  
  187.     /** Returns the Border of the MenuView's Menu.
  188.       */
  189.     public Border border() {
  190.         return menu.border();
  191.     }
  192.  
  193.     /** Sets the MenuView to be transparent or opaque. This will also set the
  194.       * transparency for the InternalWindow this MenuView draws into.
  195.       */
  196.     public void setTransparent(boolean flag) {
  197.         transparent = flag;
  198.         menuWindow.setTransparent(flag);
  199.     }
  200.  
  201.     /** Overridden to return <b>true</b> if the MenuView is transparent.
  202.       * @see #setTransparent
  203.       */
  204.     public boolean isTransparent() {
  205.         return transparent;
  206.     }
  207.  
  208.     /** Sets the height of each MenuItem in the MenuView. Each MenuItem has
  209.       * the same height. If <b>height</b> is 0, sets the height to
  210.       * <b>minItemHeight()</b>.
  211.       * @see #minItemHeight
  212.       */
  213.     public void setItemHeight(int height) {
  214.         if (height > 0)
  215.             itemHeight = height;
  216.         else
  217.             itemHeight = minItemHeight();
  218.     }
  219.  
  220.     /** Returns the MenuView's MenuItem height.
  221.       * @see #setItemHeight
  222.       */
  223.     public int itemHeight() {
  224.         if (itemHeight > 0)
  225.             return itemHeight;
  226.  
  227.         setItemHeight(minItemHeight());
  228.         return itemHeight;
  229.     }
  230.  
  231.     /** Returns the largest <b>minHeight()</b> of all of the MenuView's
  232.       * MenuItems.
  233.       */
  234.     public int minItemHeight() {
  235.         int    i, minHeight, height, count;
  236.  
  237.         minHeight = 0;
  238.         count = menu.itemCount();
  239.         for (i = 0; i < count; i++) {
  240.             height = menu.itemAt(i).minHeight();
  241.  
  242.             if (height > minHeight) {
  243.                 minHeight = height;
  244.             }
  245.         }
  246.         return minHeight;
  247.     }
  248.  
  249.     /** Returns the largest title width of all of the MenuView's MenuItems.
  250.       */
  251.     public int minItemWidth() {
  252.         int          i, width, maxWidth;
  253.  
  254.         maxWidth = 0;
  255.         for (i = 0; i < menu.itemCount(); i++) {
  256.             width = menu.itemAt(i).minWidth();
  257.  
  258.             if (width > maxWidth) {
  259.                 maxWidth = width;
  260.             }
  261.         }
  262.         return maxWidth;
  263.     }
  264.  
  265.     /** Overridden to return a Size consisting of the minimum width necessary
  266.       * to accommodate all the MenuItems and the <b>itemHeight()</b>.
  267.       * This Size will reflect whether or not this MenuView is of type
  268.       * <b>HORIZONTAL</b> or <b>VERTICAL</b>.
  269.       */
  270.     public Size minSize() {
  271.         int width, height, count, i;
  272.         MenuItem item;
  273.  
  274.         count = menu.itemCount();
  275.  
  276.         if (type == HORIZONTAL) {
  277.             width = 0;
  278.             for (i = 0; i < count; i++) {
  279.                 item = menu.itemAt(i);
  280.                 width += item.minWidth();
  281.             }
  282.             height = itemHeight();
  283.         } else {
  284.             width = minItemWidth();
  285.             height = count * itemHeight();
  286.         }
  287.  
  288.         width += border().widthMargin();
  289.         height += border().heightMargin();
  290.  
  291.         return new Size(width, height);
  292.     }
  293.  
  294.     /** Returns the MenuItem at the coordinate (<b>x</b>, <b>y</b>).
  295.       */
  296.     public MenuItem itemForPoint(int x, int y) {
  297.         int       i, index;
  298.         MenuItem  item;
  299.         Rect      itemRect;
  300.  
  301.         index = -1;
  302.         for (i = 0; i < menu.itemCount(); i++) {
  303.             itemRect = rectForItemAt(i);
  304.             if (itemRect.contains(x, y)) {
  305.                 index = i;
  306.                 break;
  307.             }
  308.         }
  309.  
  310.         if (index >= 0) {
  311.             item = menu.itemAt(index);
  312.         } else {
  313.             item = null;
  314.         }
  315.         return item;
  316.     }
  317.  
  318.     /** Returns the row of the selected MenuItem. If no MenuItem is selected,
  319.       * returns -1.
  320.       */
  321.     public int selectedIndex() {
  322.         MenuItem item;
  323.  
  324.         item = selectedItem();
  325.  
  326.         if (item == null) {
  327.             return -1;
  328.         }
  329.  
  330.         return menu.indexOfItem(item);
  331.     }
  332.  
  333.     /** Returns the selected MenuItem. If no MenuItem is selected, returns
  334.       * null.
  335.       */
  336.     public MenuItem selectedItem() {
  337.         return selectedItem;
  338.     }
  339.  
  340.     /** Selects <b>item</b> and deselects any other selected MenuItem.
  341.       */
  342.     public void selectItem(MenuItem item) {
  343.         if (!item.isEnabled()) {
  344.             return;
  345.         }
  346.  
  347.         if (selectedItem != item) {
  348.             if (selectedItem != null) {
  349.                 selectedItem.setSelected(false);
  350.                 addDirtyRect(rectForItemAt(menu.indexOfItem(selectedItem)));
  351.             }
  352.             item.setSelected(true);
  353.             selectedItem = item;
  354.             addDirtyRect(rectForItemAt(menu.indexOfItem(item)));
  355.         }
  356.     }
  357.  
  358.     /** Deselects any MenuItem that might be currently selected.
  359.       */
  360.     public void deselectItem() {
  361.         if (selectedItem != null) {
  362.             selectedItem.setSelected(false);
  363.             addDirtyRect(rectForItemAt(menu.indexOfItem(selectedItem)));
  364.             selectedItem = null;
  365.         }
  366.     }
  367.  
  368.     /** Returns the Rect that describes the MenuItem at <b>index</b>.
  369.       */
  370.     public Rect rectForItemAt(int index) {
  371.         Rect      itemRect;
  372.         MenuItem  item;
  373.         int       i, x, y, width;
  374.  
  375.         if (index < 0 || index >= menu.itemCount())
  376.             return null;
  377.  
  378.         x = 0;
  379.         if (type == HORIZONTAL) {
  380.             y = 0;
  381.             for (i = 0; i < index; i++) {
  382.                 item = menu.itemAt(i);
  383.                 x += item.minWidth();
  384.             }
  385.             width = menu.itemAt(index).minWidth();
  386.         } else {
  387.             y = itemHeight() * index;
  388.             width = bounds.width - border().widthMargin();
  389.         }
  390.  
  391.         x += border().leftMargin();
  392.         y += border().topMargin();
  393.  
  394.         itemRect = Rect.newRect(x, y, width, itemHeight());
  395.         return itemRect;
  396.     }
  397.  
  398.     /** Returns a Rect describing the MenuView's "interior," the MenuView's
  399.       * bounds minus its left, right, top and bottom borders.
  400.       */
  401.     public Rect interiorRect() {
  402.         Rect interiorRect;
  403.  
  404.         interiorRect = new Rect(border().leftMargin(),
  405.                                 border().topMargin(),
  406.                                 bounds.width - border().widthMargin(),
  407.                                 bounds.height - border().heightMargin());
  408.         return interiorRect;
  409.     }
  410.  
  411.     /** Calls <b>draw()</b> with the Rect for the MenuItem at the given row
  412.       * index.
  413.       */
  414.     public void drawItemAt(int index) {
  415.         Rect rect = rectForItemAt(index);
  416.         draw(rect);
  417.     }
  418.  
  419.     /** Returns a MenuView with its structure defined by <b>theMenu</b>.
  420.       * Subclasses of MenuView should override this method to return
  421.       * their special subclass.
  422.       */
  423.     protected MenuView createMenuView(Menu theMenu) {
  424.         return new MenuView(0, 0, 0, 0, theMenu, this);
  425.     }
  426.  
  427.     /** Climbs the ownership tree to find the top-level MenuView.  Top-level
  428.       * MenuViews have a null owner, as well as a top-level Menu.
  429.       * @see #setOwner
  430.       */
  431.     MenuView mainOwner() {
  432.         MenuView   myOwner;
  433.  
  434.         myOwner = owner;
  435.         while (myOwner.owner() != null) {
  436.             myOwner = myOwner.owner();
  437.         }
  438.  
  439.         return myOwner;
  440.     }
  441.  
  442.     /** Overridden from View to collect <i>all</i> KeyStrokes and forward
  443.       * them to the Menu for processing.
  444.       */
  445.     boolean performCommandForKeyStroke(KeyStroke aKeyStroke, int condition) {
  446.         if (Application.application().activeMenuViews.count() > 0) {
  447.             return false;
  448.         }
  449.         if (window() != null) {
  450.             if (!this.descendsFrom(rootView()._mainWindow)) {
  451.                 return false;
  452.             }
  453.         }
  454.         if (condition == View.ALWAYS || condition == View.WHEN_IN_MAIN_WINDOW) {
  455.             KeyEvent event = new KeyEvent((long)0, aKeyStroke.key,
  456.                                           aKeyStroke.modifiers, true);
  457.             return menu.handleCommandKeyEvent(event);
  458.         }
  459.         return false;
  460.     }
  461.  
  462.     /** Called by Application on any MenuViews that are
  463.       * registered for notification.  This should only be called by
  464.       * Application, and is intended only for top-level MenuViews.
  465.       */
  466.     void mouseWillDown(MouseEvent event) {
  467.         Rect        rect;
  468.         MenuView    myChild;
  469.         MouseEvent  newEvent;
  470.         RootView    firstRootView;
  471.  
  472.         firstRootView = Application.application().firstRootView();
  473.         if (firstRootView != rootView()) {
  474.             hideAll();
  475.             return;
  476.         }
  477.  
  478.         newEvent = rootView().convertEventToView(this, event);
  479.         if (containsPoint(newEvent.x, newEvent.y)) {
  480.             return;
  481.         }
  482.  
  483.         if (selectedItem() != null) {
  484.             myChild = child;
  485.             while (myChild != null) {
  486.                 rect = new Rect(myChild.bounds);
  487.                 myChild.superview().convertRectToView(null, rect, rect);
  488.                 if (Rect.contains(rect.x, rect.y, rect.width, rect.height,
  489.                                   event.x, event.y)) {
  490.                     return;
  491.                 }
  492.                 myChild = myChild.child;
  493.             }
  494.         }
  495.  
  496.         hideAll();
  497.     }
  498.  
  499.     void hideAll() {
  500.         Application.application().removeActiveMenuView(this);
  501.         if (child != null) {
  502.             child.hide();
  503.         }
  504.         if (isVisible()) {
  505.             hide();
  506.         }
  507.         deselectItem();
  508.     }
  509.  
  510.     /** Overridden to receive mouse clicks.
  511.       */
  512.     public boolean mouseDown(MouseEvent event) {
  513.         MenuItem  clickedItem;
  514.  
  515.         if (owner != null) {
  516.             return true;
  517.         }
  518.  
  519.         clickedItem = itemForPoint(event.x, event.y);
  520.         if (clickedItem == null || !clickedItem.isEnabled()) {
  521.             if (child != null) {
  522.                 child.hide();
  523.             }
  524.             deselectItem();
  525.             return true;
  526.         }
  527.  
  528.         if (selectedItem != null && clickedItem == selectedItem) {
  529.             if (isVisible()) {
  530.                 return true;
  531.             }
  532.             Application.application().removeActiveMenuView(this);
  533.             if (child != null) {
  534.                 child.hide();
  535.                 child = null;
  536.             }
  537.             deselectItem();
  538.             return true;
  539.         }
  540.  
  541.         selectItem(clickedItem);
  542.  
  543.         if (clickedItem.isEnabled() && clickedItem.hasSubmenu()) {
  544.             MenuView menuView = createMenuView(clickedItem.submenu());
  545.             menuView.show(rootView(), event);
  546.             child = menuView;
  547.         }
  548.  
  549.         return true;
  550.     }
  551.  
  552.     /** Overridden to receive mouse drag events.
  553.       */
  554.     public void mouseDragged(MouseEvent event) {
  555.         MenuItem        clickedItem;
  556.         MouseEvent      newEvent;
  557.         MenuView        menuView;
  558.         int             i;
  559.  
  560.  
  561.         clickedItem = itemForPoint(event.x, event.y);
  562.  
  563.         if (!Rect.contains(0, 0, width(), height(), event.x, event.y)) {
  564.             clickedItem = null;
  565.             if (owner != null && child == null ||
  566.                        owner == null && child == null && isVisible()) {
  567.                 deselectItem();
  568.             }
  569.         }
  570.  
  571.         if (clickedItem != null && !clickedItem.isEnabled()) {
  572.             return;
  573.         }
  574.  
  575.         menuView = child;
  576.         while (menuView != null && menuView.isVisible()) {
  577.             Rect rect = new Rect(menuView.bounds);
  578.             newEvent = convertEventToView(menuView, event);
  579.             if (Rect.contains(rect.x, rect.y, rect.width, rect.height,
  580.                               newEvent.x, newEvent.y)) {
  581.                 clickedItem = menuView.itemForPoint(newEvent.x, newEvent.y);
  582.                 if (clickedItem != null) {
  583.                     menuView.mouseDragged(newEvent);
  584.                     menuView.autoscroll(newEvent);
  585.                     return;
  586.                 }
  587.             } else if (menuView.child == null) {
  588.                 if (menuView.selectedItem() == null) {
  589.                     menuView.autoscroll(newEvent);
  590.                 }
  591.                 menuView.deselectItem();
  592.             }
  593.             menuView = menuView.child;
  594.         }
  595.  
  596.         if (clickedItem != null && clickedItem != selectedItem()) {
  597.             if (selectedItem != null && selectedItem.hasSubmenu() &&
  598.                     child != null && child.isVisible()) {
  599.                 child.hide();
  600.                 child = null;
  601.             }
  602.             selectItem(clickedItem);
  603.             if (clickedItem.hasSubmenu()) {
  604.                 menuView = createMenuView(clickedItem.submenu());
  605.                 menuView.show(rootView(), event);
  606.                 child = menuView;
  607.             }
  608.         }
  609.     }
  610.  
  611.     /** Overridden to receive mouse up events.
  612.       */
  613.     public void mouseUp(MouseEvent event) {
  614.         int       i;
  615.         MenuItem  clickedItem = null;
  616.         MenuView  menuView;
  617.  
  618.         clickedItem = itemForPoint(event.x, event.y);
  619.         if (owner == null && selectedItem == clickedItem) {
  620.             if (isVisible() && selectedItem != null) {
  621.                 Application.application().removeActiveMenuView(this);
  622.                 hide();
  623.                 menu.performCommand("", clickedItem);
  624.             } else {
  625.                 return;
  626.             }
  627.         }
  628.  
  629.         if (owner == null && clickedItem == null) {
  630.             menuView = child;
  631.             while (menuView.child != null) {
  632.                 menuView = menuView.child;
  633.             }
  634.             menuView.mouseUp(convertEventToView(menuView, event));
  635.         }
  636.  
  637.         if (owner != null && selectedItem != null) {
  638.             clickedItem = selectedItem;
  639.             Application.application().removeActiveMenuView(mainOwner());
  640.             hide();
  641.             menuView = owner;
  642.             while (menuView.owner() != null) {
  643.                 menuView.hide();
  644.                 menuView = menuView.owner();
  645.             }
  646.             menuView.hide();
  647.             menu.performCommand("", clickedItem);
  648.         }
  649.     }
  650.  
  651.     /** Overridden to receive mouse entered events.
  652.       */
  653.     public void mouseEntered(MouseEvent event) {
  654.         if ((owner == null && selectedItem != null) || isVisible()) {
  655.             mouseDragged(event);
  656.         }
  657.     }
  658.  
  659.     /** Overridden to receive mouse moved events.
  660.       */
  661.     public void mouseMoved(MouseEvent event) {
  662.         if ((owner == null && selectedItem != null) || isVisible()) {
  663.             mouseDragged(event);
  664.         }
  665.     }
  666.  
  667.     /** Overridden to receive mouse exited events.
  668.       */
  669.     public void mouseExited(MouseEvent event) {
  670.         if ((owner == null && selectedItem != null) || isVisible()) {
  671.             mouseDragged(event);
  672.         }
  673.     }
  674.  
  675.     /** Overridden to draw this MenuView.  This handles both top-level and
  676.       * submenu type MenuViews.
  677.       */
  678.     public void drawView(Graphics g) {
  679.         Rect      itemRect, clipRect;
  680.         MenuItem  item;
  681.         int       i, count, width;
  682.         boolean   flag;
  683.  
  684.         border().drawInRect(g, 0, 0, width(), height());
  685.  
  686.         count = menu.itemCount();
  687.  
  688.         width = 0;
  689.         for (i = 0; i < count; i++) {
  690.             item = menu.itemAt(i);
  691.             itemRect = rectForItemAt(i);
  692.             width += itemRect.width;
  693.  
  694.             if (!g.clipRect().intersects(itemRect)) {
  695.                 continue;
  696.             }
  697.  
  698.             g.pushState();
  699.             g.setClipRect(itemRect);
  700.  
  701.             if (!isTransparent()) {
  702.                 g.setColor(backgroundColor());
  703.                 g.fillRect(itemRect.x, itemRect.y, itemRect.width,
  704.                            itemRect.height);
  705.             }
  706.             if (type == HORIZONTAL) {
  707.                 flag = false;
  708.             } else {
  709.                 flag = true;
  710.             }
  711.             item.drawInRect(g, itemRect, flag);
  712.             g.popState();
  713.  
  714.             Rect.returnRect(itemRect);
  715.         }
  716.         if (width < interiorRect().width && type == HORIZONTAL &&
  717.                !isTransparent()) {
  718.             g.setColor(backgroundColor());
  719.             g.fillRect(interiorRect().x + width, interiorRect().y,
  720.                        interiorRect().width - width, interiorRect().height);
  721.         }
  722.     }
  723.  
  724.     /** Shows the InternalWindow that holds this MenuView.  This method
  725.       * is automatically called by this MenuView's owner when it should
  726.       * show. You should not call this method on
  727.       * a MenuView that has been added to a Window with <b>setMenuView</b>.
  728.       * You should only call this method directly on top-level
  729.       * context-sensitive MenuViews. In this case, <b>rootView</b> is the view
  730.       * in which to show the InternalWindow containing the context-sensitive MenuView.
  731.       * <b>event</b> should be in the coordinate system of <b>rootView</b> and
  732.       * the (x, y) values of the event become the origin of the InternalWindow.
  733.       */
  734.     public void show(RootView rootView, MouseEvent event) {
  735.         Rect     windowRect, itemRect;
  736.         int      width, height, i, x, y;
  737.         Menu     theMenu;
  738.         MenuView menuView;
  739.  
  740.         if (menu.itemCount() == 0) {
  741.             return;
  742.         }
  743.  
  744.         width = minItemWidth() + border().widthMargin() + 20;   // ALERT!
  745.         height = (itemHeight() * menu.itemCount()) + border().heightMargin();
  746.  
  747.         sizeTo(width, height);
  748.  
  749.         if (menu.superitem() != null) {
  750.             theMenu = menu.superitem().supermenu();
  751.         } else {
  752.             theMenu = menu;
  753.         }
  754.  
  755.         if (owner != null) {
  756.             menuView = owner;
  757.         } else {
  758.             menuView = this;
  759.         }
  760.  
  761.         windowRect = Rect.newRect(0, 0, width(), height());
  762.  
  763.         menuView.convertRectToView(null, windowRect, windowRect);
  764.  
  765.         if (rootView.windowClipView() != null && menuWindow.layer() !=
  766.                               InternalWindow.IGNORE_WINDOW_CLIPVIEW_LAYER+11) {
  767.             rootView.convertRectToView(rootView.windowClipView(),
  768.                                        windowRect, windowRect);
  769.         }
  770.  
  771.         itemRect = menuView.rectForItemAt(menuView.selectedIndex());
  772.         if (itemRect == null) {
  773.             itemRect = new Rect(0, 0, 0, 0);
  774.         }
  775.  
  776.         if (theMenu.isTopLevel() && menuView.type == HORIZONTAL) {
  777.             x = windowRect.x + itemRect.x - menuView.border().leftMargin();
  778.             y = windowRect.y + menuView.height();
  779.         } else if (menu.isTopLevel() && type == VERTICAL) {
  780.             x = event.x;
  781.             y = event.y;
  782.         } else {
  783.             x = windowRect.x + itemRect.width +
  784.                       menuView.border().widthMargin() - 3;  // ALERT
  785.             y = windowRect.y + itemRect.maxY() - itemRect.height -
  786.                                   menuView.border().topMargin();
  787.         }
  788.  
  789.         // ALERT!  If we have a context-sensitive top-level Menu, it has
  790.         // horizontal resize instructions, so we have to counteract them
  791.         int w = width();
  792.         menuWindow.setBounds(x, y, width(), height());
  793.         sizeTo(w, height());
  794.  
  795.         Rect.returnRect(windowRect);
  796.         Rect.returnRect(itemRect);
  797.  
  798.         if (owner != null) {
  799.             menuView = mainOwner();
  800.         } else {
  801.             menuView = this;
  802.         }
  803.         Application.application().addActiveMenuView(menuView);
  804.  
  805.         menuWindow.setRootView(rootView);
  806.         menuWindow.show();
  807.     }
  808.  
  809.     /** Hides the InternalWindow that holds this MenuView. This method is
  810.       * automatically called by this MenuView's owner when it should
  811.       * hide.
  812.       * @see #show
  813.       */
  814.     public void hide() {
  815.         MenuItem   item;
  816.         MenuView   menuView;
  817.  
  818.         if (menuWindow.isVisible()) {
  819.             menuWindow.hide();
  820.         }
  821.  
  822.         if (selectedItem != null && selectedItem.hasSubmenu()) {
  823.             child.hide();
  824.             child = null;
  825.         }
  826.         deselectItem();
  827.     }
  828.  
  829.     /** Returns <b>true</b> if this MenuView is visible by virtue of its
  830.       * InternalWindow.
  831.       */
  832.     public boolean isVisible() {
  833.         return menuWindow.isVisible();
  834.     }
  835.  
  836.     /** Overriden to return <b>true</b>.
  837.       */
  838.     public boolean wantsAutoscrollEvents() {
  839.         return true;
  840.     }
  841.  
  842.     /** Magic autoscroller. Called in mouseDragged by top-most MenuView, when
  843.       * it knows the MenuView in question should scroll. Taken from ListView.
  844.       */
  845.     void autoscroll(MouseEvent event) {
  846.         Rect visibleRect;
  847.  
  848.         visibleRect = Rect.newRect();
  849.         computeVisibleRect(visibleRect);
  850.  
  851.         if (!visibleRect.contains(event.x, event.y)) {
  852.             if (event.y < visibleRect.y) {
  853.                 Rect tmpRect = Rect.newRect(visibleRect.x, event.y,
  854.                                             visibleRect.width,
  855.                                             itemHeight());
  856.                 scrollRectToVisible(tmpRect);
  857.                 Rect.returnRect(tmpRect);
  858.             } else if (event.y > visibleRect.maxY()) {
  859.                 Rect tmpRect = Rect.newRect(visibleRect.x, event.y -
  860.                                             itemHeight(),
  861.                                             visibleRect.width,
  862.                                             itemHeight());
  863.                 scrollRectToVisible(tmpRect);
  864.                 Rect.returnRect(tmpRect);
  865.             }
  866.         }
  867.         Rect.returnRect(visibleRect);
  868.     }
  869.  
  870.     /** Describes the MenuView class' information.
  871.       * @see Codable#describeClassInfo
  872.       */
  873.     public void describeClassInfo(ClassInfo info) {
  874.         super.describeClassInfo(info);
  875.  
  876.         info.addClass("netscape.application.MenuView", 1);
  877.         info.addField(MENU_KEY, OBJECT_TYPE);
  878.         info.addField(OWNER_KEY, OBJECT_TYPE);
  879.         info.addField(CHILD_KEY, OBJECT_TYPE);
  880.         info.addField(MENUWINDOW_KEY, OBJECT_TYPE);
  881.  
  882.         info.addField(MENUITEMHEIGHT_KEY, INT_TYPE);
  883.         info.addField(TYPE_KEY, INT_TYPE);
  884.  
  885.         info.addField(TRANSPARENT_KEY, BOOLEAN_TYPE);
  886.     }
  887.  
  888.     /** Encodes the MenuView instance.
  889.       * @see Codable#decode
  890.       */
  891.     public void encode(Encoder encoder) throws CodingException {
  892.         super.encode(encoder);
  893.  
  894.         encoder.encodeObject(MENU_KEY, menu);
  895.         encoder.encodeObject(OWNER_KEY, owner);
  896.         encoder.encodeObject(CHILD_KEY, child);
  897.         encoder.encodeObject(MENUWINDOW_KEY, menuWindow);
  898.  
  899.         encoder.encodeInt(MENUITEMHEIGHT_KEY, itemHeight);
  900.         encoder.encodeInt(TYPE_KEY, type);
  901.  
  902.         encoder.encodeBoolean(TRANSPARENT_KEY, transparent);
  903.     }
  904.  
  905.     /** Decodes the MenuView instance.
  906.       * @see Codable#decode
  907.       */
  908.     public void decode(Decoder decoder) throws CodingException {
  909.         super.decode(decoder);
  910.  
  911.         menu = (Menu)decoder.decodeObject(MENU_KEY);
  912.         owner = (MenuView)decoder.decodeObject(OWNER_KEY);
  913.         child = (MenuView)decoder.decodeObject(CHILD_KEY);
  914.         menuWindow = (InternalWindow)decoder.decodeObject(MENUWINDOW_KEY);
  915.  
  916.         itemHeight = (int)decoder.decodeInt(MENUITEMHEIGHT_KEY);
  917.         type = (int)decoder.decodeInt(TYPE_KEY);
  918.  
  919.         transparent = (boolean)decoder.decodeBoolean(TRANSPARENT_KEY);
  920.     }
  921.  
  922.     /** Finishes the MenuView instance decoding.
  923.       * @see Codable#finishDecoding
  924.       */
  925.     public void finishDecoding() throws CodingException {
  926.         super.finishDecoding();
  927.     }
  928. }
  929.